home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / tracker-4.13.lha / tracker / Arch / Hpux / 3_audio.c next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  10.3 KB  |  464 lines

  1. /* -*-C-*-
  2.     vi:ts=3 sw=3:
  3. *******************************************************************************
  4. *
  5. * File:        hpux_audio.c
  6. * RCS:        $Header: /users/algo/espie/projects/tracker/Arch/Hpux/RCS/3_audio.c,v 1.1 1995/02/01 16:43:47 espie Exp $
  7. * Description:    HP-UX audio hardware interface for tracker
  8. * Author:    Darryl Okahata (darrylo@sr.hp.com)
  9. * Created:    Thu Dec 16 12:09:53 1993
  10. * Modified:     Mon Dec 20 12:17:02 1993 (Darryl Okahata) darrylo@mina
  11. * Language:    C
  12. * Package:    N/A
  13. * Status:    Experimental
  14. *
  15. * (C) Copyright 1993, Hewlett-Packard, all rights reserved.
  16. *
  17. *******************************************************************************
  18.  
  19.  */
  20.  
  21. #include "defs.h"
  22. #include <errno.h>
  23. #include <sys/socket.h>
  24.  
  25. #include <audio/Alib.h>
  26.  
  27. #include "extern.h"
  28.  
  29.  
  30.  
  31. #define abs(x) ((x) < 0 ? -(x) : (x))
  32.  
  33. #define STEREO_CHANNELS        (ALeftOutputChMask | ARightOutputChMask)
  34.  
  35. extern AGainDB        volume;        /* volume in dB -- in main.c */
  36. extern char        use_speaker;    /* in main.c */
  37.  
  38. LOCAL Audio        *audio;
  39. LOCAL ADataFormat    *available_formats;
  40. LOCAL long        available_formats_len;
  41. LOCAL AOutputChMask    available_channels;
  42. LOCAL AByteOrder    byte_order;
  43. LOCAL AudioAttributes    audio_attributes;
  44. LOCAL AGainEntry    gain_entry[4];
  45. LOCAL SSPlayParams    stream_parameters;
  46. LOCAL ATransID        xid;
  47. LOCAL SStream        audio_stream;
  48. LOCAL int        stream_socket;
  49.  
  50.  
  51. LOCAL int        stereo;
  52. LOCAL int        primary, secondary = 512;
  53. LOCAL ADataFormat    audio_format;
  54. LOCAL int        index, max_index;
  55. LOCAL long        buffer_size;
  56. LOCAL char        *buffer;
  57. LOCAL short        *sbuffer;
  58.  
  59.  
  60. LOCAL int round_sampling_rate(audio, f)
  61. Audio    *audio;
  62. int    f;
  63. {
  64.     int best = 0;
  65.     int i;
  66.  
  67.     for (i = 0; i < audio->n_sampling_rate; i++) {
  68.     if (abs(audio->sampling_rate_list[i] - f) < abs(best - f)) {
  69.         best = audio->sampling_rate_list[i];
  70.     }
  71.     }
  72.     return best;
  73. }
  74.  
  75.  
  76. LOCAL format_available(fmt)
  77. ADataFormat    fmt;
  78. {
  79.     int        i;
  80.  
  81.     for (i = 0; i < available_formats_len; ++i) {
  82.     if (available_formats[i] == fmt) {
  83.         break;
  84.     }
  85.     }
  86.     if (i >= available_formats_len) {
  87.     return (0);
  88.     }
  89.     return (1);
  90. }
  91.  
  92.  
  93. void set_mix(percent)
  94. int percent;
  95. {
  96.     percent *= 256;
  97.     percent /= 100;
  98.     primary = percent;
  99.     secondary = 512 - percent;
  100. }
  101.  
  102.  
  103. /*
  104.  * It would be nice if we could use AGetErrorText(), but this requires that
  105.  * an audio pointer be passed to it, and this pointer could be NULL.
  106.  */
  107. LOCAL void die(msg, error)
  108. char        *msg;
  109. AError        error;
  110. {
  111.     char    *errbuf, buf[1000];    /* memory is cheap, life is short */
  112.  
  113.     if (msg == NULL) {
  114.     msg = "";
  115.     }
  116.     switch (error) {
  117.     case AENoError:
  118.     errbuf = "(No audio error -- huh?  This should never happen!)";
  119.     break;
  120.     case AESystemCall:
  121.     errbuf = "System call error";
  122.     break;
  123.     case AEBadAudio:
  124.     errbuf = "Bad audio";
  125.     break;
  126.     case AEBadValue:
  127.     errbuf = "Bad audio value";
  128.     break;
  129.     case AEHostNotFound:
  130.     errbuf = "Audio host not found";
  131.     break;
  132.     case AENoSuchAudioNumber:
  133.     errbuf = "No such audio number";
  134.     break;
  135.     case AEBadFileFormat:
  136.     errbuf = "Bad audio file format";
  137.     break;
  138.     case AEBadDataFormat:
  139.     errbuf = "Bad audio data format";
  140.     break;
  141.     case AEFileNotFound:
  142.     errbuf = "Audio file not found";
  143.     break;
  144.     case AEBadLinkID:
  145.     errbuf = "Audio bad link ID";
  146.     break;
  147.     case AEBadGainMatrix:
  148.     errbuf = "Bad audio gain matrix";
  149.     break;
  150.     case AEBadFileHdr:
  151.     errbuf = "Bad audio file header";
  152.     break;
  153.     case AEUnrecognizableFormat:
  154.     errbuf = "Unrecognizable audio format";
  155.     break;
  156.     case AEBadAttribute:
  157.     errbuf = "Bad audio attribute";
  158.     break;
  159.     case AEBadOffset:
  160.     errbuf = "Audio bad offset";
  161.     break;
  162.     case AEBadTransactionID:
  163.     errbuf = "Bad audio transaction ID";
  164.     break;
  165.     case AECantDetermineFormat:
  166.     errbuf = "Audio can't determine format";
  167.     break;
  168.     case AEOutOfMemory:
  169.     errbuf = "out of memory (audio)";
  170.     break;
  171.     case AEOpenFailed:
  172.     errbuf = "Audio open failed";
  173.     break;
  174.     case AEBadSamplingRate:
  175.     errbuf = "Bad audio sampling rate";
  176.     break;
  177.     case AEBadSoundBucket:
  178.     errbuf = "Audio bad sound bucket";
  179.     break;
  180.     case AEBadSoundStream:
  181.     errbuf = "Audio bad sound stream";
  182.     break;
  183.     case AETransactionBusy:
  184.     errbuf = "Audio transaction busy";
  185.     break;
  186.     case AEllbdNotStarted:
  187.     errbuf = "llbd daemon not running";
  188.     break;
  189.     case AERPCFailed:
  190.     errbuf = "Audio RPC failed";
  191.     break;
  192.     case AELibraryMismatch:
  193.     errbuf = "Audio library mismatch";
  194.     break;
  195.     default:
  196.     sprintf(buf, "(unknown audio error %d)", (int) error);
  197.     errbuf = buf;
  198.     break;
  199.     }
  200.      notice(msg);
  201.      end_all(errbuf);
  202. }
  203.  
  204.  
  205. int open_audio(freq, stereo_flag)
  206. int freq;
  207. int stereo_flag;
  208. {
  209.     long        status_return;
  210.     AudioAttrMask    valid_attributes;
  211.     char        *speaker;
  212.     int            dsize, i;
  213.  
  214.     stereo = stereo_flag;
  215.  
  216.     if ((audio = AOpenAudio(NULL, &status_return)) == NULL) {
  217.     die("could not open audio: ", status_return);
  218.     }
  219.  
  220.     available_formats = ADataFormats(audio);
  221.     available_formats_len = ANumDataFormats(audio);
  222.     if (format_available(ADFLin16)) {
  223.     audio_format = ADFLin16;
  224.     dsize = 2;        /* for ADFLin16 */
  225.     } else if (format_available(ADFLin8)) {
  226.     audio_format = ADFLin8;
  227.     dsize = 1;        /* for ADFLin8 */
  228.     } else {
  229.      end_all("Neither ADFLin16/ADFLin8 supported by the audio device");
  230.     }
  231.  
  232.     available_channels = AOutputChannels(audio);
  233.  
  234.     valid_attributes = ASDataFormatMask | ASBitsPerSampleMask |
  235.     ASSamplingRateMask | ASChannelsMask;
  236.     audio_attributes = *ABestAudioAttributes(audio);
  237.     audio_attributes.type = ATSampled;
  238.     audio_attributes.attr.sampled_attr.data_format = ADFLin16;
  239.     audio_attributes.attr.sampled_attr.bits_per_sample = 16;
  240.  
  241.     if (freq <= 0) {
  242.     /*
  243.      * Use value closest to CD-quality audio
  244.      */
  245.     freq = 44100;
  246.     }
  247.     freq = round_sampling_rate(audio, freq);
  248.     audio_attributes.attr.sampled_attr.sampling_rate = freq;
  249.  
  250.     audio_attributes.attr.sampled_attr.duration.type = ATTFullLength;
  251.     valid_attributes |= ASDurationMask;
  252.  
  253.     if (stereo &&
  254.     ((available_channels & (STEREO_CHANNELS)) == STEREO_CHANNELS)) {
  255.     audio_attributes.attr.sampled_attr.channels = 2;
  256.     audio_attributes.attr.sampled_attr.interleave = 1;
  257.     valid_attributes |= ASInterleaveMask;
  258.     } else {
  259.     audio_attributes.attr.sampled_attr.channels = 1;
  260.     }
  261.  
  262.     /*
  263.      * Select attributes for playback
  264.      */
  265.     AChoosePlayAttributes(audio, ABestAudioAttributes(audio),
  266.               valid_attributes, &audio_attributes,
  267.               &byte_order, &status_return);
  268.     if (byte_order != AMSBFirst) {
  269.      end_all("Little endian byte ordering not supported");
  270.     }
  271.  
  272.     /*
  273.      * Use the external jack, unless the user overrides this on the
  274.      * command-line, or SPEAKER is set.     (The command line stuff is done in
  275.      * main.c.)
  276.      */
  277.     if ((speaker = getenv( "SPEAKER" )) != NULL) {
  278.     if ((*speaker == 'i') || (*speaker == 'I')) {
  279.         use_speaker = 1;
  280.     }
  281.     }
  282.  
  283.     stream_parameters.priority = APriorityNormal;
  284.  
  285.     switch(audio_attributes.attr.sampled_attr.channels) {
  286.     case 1:
  287.     gain_entry[0].u.o.out_ch = AOCTMono;
  288.     gain_entry[0].gain = volume;
  289.     gain_entry[0].u.o.out_dst =
  290.         (use_speaker) ? AODTMonoIntSpeaker : AODTMonoJack;
  291.     break;
  292.     case 2:
  293.     default:    /* assume no more than 2 channels */
  294.     gain_entry[0].u.o.out_ch = AOCTLeft;
  295.     gain_entry[0].gain = volume;
  296.     gain_entry[0].u.o.out_dst =
  297.         (use_speaker) ? AODTLeftIntSpeaker : AODTLeftJack;
  298.     gain_entry[1].u.o.out_ch = AOCTRight;
  299.     gain_entry[1].gain = volume;
  300.     gain_entry[1].u.o.out_dst =
  301.         (use_speaker) ? AODTRightIntSpeaker : AODTRightJack;
  302.     break;
  303.     }
  304.  
  305.     stream_parameters.gain_matrix.type = AGMTOutput;       /* gain matrix */
  306.     stream_parameters.gain_matrix.num_entries =
  307.     audio_attributes.attr.sampled_attr.channels;
  308.     stream_parameters.gain_matrix.gain_entries = gain_entry;
  309.     stream_parameters.play_volume = AUnityGain;           /* play volume */
  310.     stream_parameters.event_mask = 0;               /* don't solicit any
  311.                                   events */
  312.  
  313.     /*
  314.      * create an audio stream
  315.      */
  316.     xid = APlaySStream(audio, valid_attributes, &audio_attributes,
  317.                &stream_parameters, &audio_stream, NULL);
  318.  
  319.     /*
  320.      * create a stream socket
  321.      */
  322.     stream_socket = socket(AF_INET, SOCK_STREAM, 0);
  323.     if(stream_socket < 0) {
  324.      end_all("Socket creation failed");
  325.     }
  326.  
  327.     /*
  328.      * connect the stream socket to the audio stream port
  329.      */
  330.     status_return = connect(stream_socket,
  331.                 (struct sockaddr *)&audio_stream.tcp_sockaddr,
  332.                 sizeof(struct sockaddr_in));
  333.     if(status_return < 0) {
  334.      end_all("Connect failed");
  335.     }
  336.  
  337.     buffer_size = dsize * audio_attributes.attr.sampled_attr.channels *
  338.     audio_attributes.attr.sampled_attr.sampling_rate;
  339.     buffer = (char *) malloc(buffer_size);
  340.     sbuffer = (short *) buffer;
  341.     if (!buffer) {
  342.      end_all("Unable to allocate memory for buffer");
  343.     }
  344.     switch (audio_format) {
  345.     case ADFLin16:
  346.     max_index = buffer_size / 2 - 1;
  347.     break;
  348.     case ADFLin8:
  349.     max_index = buffer_size - 1;
  350.     break;
  351.     default:
  352.         end_all("Bad");
  353.     break;
  354.     }
  355.     max_index = buffer_size;
  356.  
  357.     return (audio_attributes.attr.sampled_attr.sampling_rate);
  358. }
  359.  
  360.  
  361. void set_synchro(s)
  362. int s;
  363. {
  364.     /* not implemented */
  365. }
  366.  
  367.  
  368. int update_frequency()
  369. {
  370.     /* not implemented */
  371.     return 0;
  372. }
  373.  
  374.  
  375. void flush_buffer()
  376. {
  377.     int        len_written, len_left;
  378.     char    *buf;
  379.  
  380.     len_left = index * 2;
  381.     buf = buffer;
  382.     while (len_left > 0) {
  383.     if((len_written = write(stream_socket, buf, len_left)) < 0) {
  384.         end_all("Write failed");
  385.     }
  386.     len_left -= len_written;
  387.     buf += len_written;
  388.     }
  389.     index = 0;
  390. }
  391.  
  392.  
  393. void output_samples(left, right)
  394. int left, right;
  395. {
  396.     if (index >= max_index) {
  397.     flush_buffer();
  398.     }
  399.     if (stereo) {
  400.     int        r, l;
  401.  
  402.     r = (left * primary + right * secondary) / 256;
  403.     l = (right * primary + left * secondary) / 256;
  404.     switch (audio_format) {
  405.     case ADFLin16:
  406.         sbuffer[index++] = r;
  407.         sbuffer[index++] = l;
  408.         break;
  409.     case ADFLin8:
  410.         buffer[index++] = r / 256 + ((r & 0x80) ? 1 : 0);
  411.         buffer[index++] = l / 256 + ((l & 0x80) ? 1 : 0);
  412.         break;
  413.     default:
  414.         break;
  415.     }
  416.     } else {
  417.     switch (audio_format) {
  418.     case ADFLin16:
  419.         sbuffer[index++] = left + right;
  420.         break;
  421.     case ADFLin8:
  422.         buffer[index++] = left + right;
  423.         break;
  424.     default:
  425.         break;
  426.     }
  427.     }
  428. }
  429.  
  430.  
  431. void discard_buffer()
  432. {
  433.     /* not implemented -- is this needed??? */
  434. }
  435.  
  436.  
  437. void close_audio()
  438. {
  439.     close(stream_socket);
  440.  
  441.     /*
  442.      * set close mode to prevent playback from stopping
  443.      *    when we close audio connection
  444.      */
  445.     ASetCloseDownMode(audio, AKeepTransactions, NULL);
  446.  
  447.     /*
  448.      *    That's all, folks!
  449.      */
  450.     ACloseAudio(audio, NULL);
  451.     audio = NULL;
  452. }
  453.  
  454.  
  455. /*
  456.  * Local Variables:
  457.  * c-indent-level: 4
  458.  * c-continued-statement-offset: 4
  459.  * c-brace-offset: -4
  460.  * c-argdecl-indent: 0
  461.  * c-label-offset: -4
  462.  * End:
  463.  */
  464.